﻿import numpy as np
import cv2
import matplotlib.pyplot as plt

def bilateral_filter(image, kernel_size=5, sigma_d=75, sigma_r=75):
    # 转换为灰度图（若为彩色）
    if len(image.shape) == 3:
        image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    image = image.astype(np.float32)
    h, w = image.shape
    
    # 确保核大小为奇数
    kernel_size = max(1, kernel_size)
    if kernel_size % 2 == 0:
        kernel_size += 1
    pad = kernel_size // 2
    
    # 预计算空间高斯核
    space_kernel = np.zeros((kernel_size, kernel_size))
    for di in range(-pad, pad + 1):
        for dj in range(-pad, pad + 1):
            spatial_dist = di**2 + dj**2
            space_kernel[di + pad, dj + pad] = np.exp(-spatial_dist / (2 * sigma_d**2))
    
    # 初始化输出
    output = np.zeros_like(image)
    
    for i in range(h):
        for j in range(w):
            current_pixel = image[i, j]
            total_weight = 0.0
            filtered_value = 0.0
            
            # 遍历邻域
            for di in range(-pad, pad + 1):
                for dj in range(-pad, pad + 1):
                    ni, nj = i + di, j + dj
                    if 0 <= ni < h and 0 <= nj < w:
                        spatial_weight = space_kernel[di + pad, dj + pad]
                        intensity_diff = image[ni, nj] - current_pixel
                        range_weight = np.exp(-(intensity_diff**2) / (2 * sigma_r**2))
                        weight = spatial_weight * range_weight
                        
                        filtered_value += image[ni, nj] * weight
                        total_weight += weight
            
            if total_weight != 0:
                output[i, j] = filtered_value / total_weight
            else:
                output[i, j] = current_pixel
    
    return np.clip(output, 0, 255).astype(np.uint8)

# 读取图像并检查有效性
image = cv2.imread('Cameraman.bmp')
if image is None:
    raise ValueError("无法读取图像，请检查文件路径")

# 执行滤波
filtered_image = bilateral_filter(image)

# 使用Matplotlib显示对比
plt.figure(figsize=(12, 6))

plt.subplot(1, 2, 1)
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title('Original Image')
plt.axis('off')

plt.subplot(1, 2, 2)
plt.imshow(filtered_image, cmap='gray')
plt.title('Bilateral Filter Result')
plt.axis('off')

plt.tight_layout()
plt.show()